package com.lordjoe.collectiveintelligence;

/**
 * com.lordjoe.collectiveintelligence.PearsonDistance
 *
 * @author Steve Lewis
 * @date Feb 25, 2009
 */
public class PearsonDistance implements IDistanceMeter
{
    public static PearsonDistance[] EMPTY_ARRAY = {};
    public static Class THIS_CLASS = PearsonDistance.class;

    public static final IDistanceMeter Instance = new PearsonDistance();

    private PearsonDistance() {}

    public double distance(ICluster c1, ICluster c2)
    {
        return 1.0 - correlation(c1,c2);
    }

    public static double correlation(ICluster target, ICluster target2)
    {
        double[] tvals = target.getValues();
        double[] mvals = target2.getValues();
        int len = Math.min(tvals.length, mvals.length);
        double sum1 = sumOver(tvals, len);
        double sum2 = sumOver(mvals, len);

        double sumsq1 = sumSquare(tvals, len);
        double sumsq2 = sumSquare(mvals, len);

        int prodSum = 0;
        for (int i = 0; i < len; i++) {
            prodSum += tvals[i] * mvals[i];
        }

        double dlen = len;
        double num = prodSum - ((sum1 * sum2) / dlen);
        double dif1 = sumsq1 - (sum1 * sum1) / dlen;
        double dif2 = sumsq2 - (sum2 * sum2) / dlen;
        double denom = Math.sqrt(dif1 * dif2 );
        if(denom == 0)
            return 0;
        return num / denom;
    }

    public static double sumSquare(double[] items, double length)
    {
        double ret = 0;
        for (int i = 0; i < length; i++) {
            double val = items[i];
            ret += val * val;
        }
        return ret;
    }

    public static double sumOver(double[] items, int length)
    {
        double ret = 0;
        for (int i = 0; i < length; i++) {
            ret += items[i];
        }
        return ret;
    }

}
